#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : app_interface.py
@Author  : Link
@Time    : 2022/6/17 11:38
@Mark    :
"""
from typing import Union, List

from BenchCore.bench_interface.limit_interface import LimitTypes
from BenchCore.code_interface.ate_code import AteCore, DtrType
from BenchCore.code_interface.operator_code import LoopType
from BenchCore.stdf_interface.stdf_data_class import LimitClass
from BenchCore.stdf_interface.stdf_def_interface import Ptr
from BenchCore.variable_interface.app_variable import AppVariable
from BenchCore.variable_interface.site_variable import SiteVariable
from BenchUtils.log_utils import Print


class BenchCore(object):
    """
    测试flow中的全局变量
    存储单工位的测试数据
    按照STDF数据bit位的规则来制定部分全局flag
    Judge
    """
    running_func = None
    socket_count: int = 1
    GloOverOn = True
    var: SiteVariable = None
    app_var: AppVariable = None
    pro = None

    def per_run(self):
        """
        在flow中初始化部分参数
        :return:
        """
        pass

    def post_run(self):
        """
        单次测试结束后对SITE的操作
        :return:
        """
        pass

    def flow_run(self, func_name: str):
        """
        通过函数名的方式来定向flow并RUN
        :return:
        """
        if not hasattr(self, func_name):
            raise Exception("No Function Name: {}".format(func_name))
        func = getattr(self, func_name)
        return func()

    # ==================================================================================================== JUDGE

    @staticmethod
    def getResult(value: float, limit: LimitClass, ):
        if limit.LO_LIMIT_TYPE == LimitTypes.GE:
            if value < limit.L_LIMIT:
                return AteCore.FAIL
        if limit.LO_LIMIT_TYPE == LimitTypes.GT:
            if value <= limit.L_LIMIT:
                return AteCore.FAIL
        if limit.HI_LIMIT_TYPE == LimitTypes.LE:
            if value > limit.H_LIMIT:
                return AteCore.FAIL
        if limit.HI_LIMIT_TYPE == LimitTypes.LT:
            if value >= limit.H_LIMIT:
                return AteCore.FAIL
        return AteCore.PASS

    @staticmethod
    def setPtrResult(ptr: Ptr, limit: LimitClass, pin_name=None, ):
        ptr.TEST_NUM = limit.TEST_NUM
        ptr.TEST_TXT = limit.TEST_TXT
        if pin_name:
            ptr.TEST_TXT = ptr.TEST_TXT + "@" + pin_name
        ptr.LO_LIMIT = limit.L_LIMIT
        ptr.HI_LIMIT = limit.H_LIMIT
        ptr.UNITS = limit.UNITS
        if limit.LO_LIMIT_TYPE == LimitTypes.GE:
            ptr.PARM_FLG.set_equal_lowlimit_pass()
        if limit.LO_LIMIT_TYPE == LimitTypes.GT:
            ptr.PARM_FLG.set_equal_lowlimit_pass(False)
        if limit.HI_LIMIT_TYPE == LimitTypes.LE:
            ptr.PARM_FLG.set_equal_highlimit_pass()
        if limit.HI_LIMIT_TYPE == LimitTypes.LT:
            ptr.PARM_FLG.set_equal_highlimit_pass(False)
        if limit.LO_LIMIT_TYPE == LimitTypes.NA:
            ptr.OPT_FLAG.set_no_low_limit()
        if limit.HI_LIMIT_TYPE == LimitTypes.NA:
            ptr.OPT_FLAG.set_no_high_limit()

    def setBinResult(self, ptr: Ptr, limit: LimitClass):
        """
        Fail了才会需要设置bin
        """
        if not self.var.prr.PART_FLG.part_failed_flag():
            self.var.prr.PART_FLG.set_part_failed_flag()
            self.var.prr.PART_FLG.set_pass_fail_flag_invalid()
            self.var.prr.HARD_BIN = limit.HARD_BIN
            self.var.prr.SOFT_BIN = limit.SOFT_BIN
            # =========================================== 可以放到数据保存那块
            self.var.cache.HARD_BIN = limit.HARD_BIN
            self.var.cache.HARD_BIN_NM = limit.HARD_BIN_NAME
            self.var.cache.SOFT_BIN = limit.SOFT_BIN
            self.var.cache.SOFT_BIN_NM = limit.SOFT_BIN_NAME
            self.var.cache.BIN_P_F = "F"

    def setBinLevelPassResult(self, limit: LimitClass):
        if self.var.prr.PART_FLG.part_failed_flag():
            return
        if self.var.bin_block and limit.SET_BIN_LEVEL < self.var.prr.HARD_BIN:
            return
        self.var.bin_block = True
        self.var.prr.HARD_BIN = limit.SET_BIN_LEVEL
        self.var.prr.SOFT_BIN = limit.SET_BIN_LEVEL

        self.var.cache.HARD_BIN = limit.SET_BIN_LEVEL
        self.var.cache.HARD_BIN_NM = limit.SET_BIN_NAME
        self.var.cache.SOFT_BIN = limit.SET_BIN_LEVEL
        self.var.cache.SOFT_BIN_NM = limit.SET_BIN_NAME
        self.var.cache.BIN_P_F = "P"

    def JudgeParameters(self, value: float, limit_ref: Union[str, LimitClass], pin_name=None, ):
        """
        判定和存储数据, 并将数据结果放入到SiteVariable中
        1. 判定
        2. 确认是否fail
        3. 有异常的话会更新给SiteVariable的prr
        4. 测试途中判定是否PASS还是FAIL
        :param value: 测试数据
        :param limit_ref: 测试项目名称
        :param pin_name: 不仅可以做为pin name
        :return:
        """
        if not isinstance(value, float):
            value = float(value)
        if isinstance(limit_ref, LimitClass):
            limits: List[LimitClass] = [limit_ref]
        else:
            limits: [LimitClass] = self.app_var.limit[limit_ref]
            if limits is None:
                raise Exception("Error, No Limit File By Key: {}".format(limit_ref))

        block_limit = None
        length = len(limits)

        if length == 1:
            """
            直接比对, Fail就退出程序
            """
            ptr = Ptr(
                HEAD_NUM=self.var.prr.HEAD_NUM,
                SITE_NUM=self.var.dut,
            )
            ptr.set_value(value)
            self.setPtrResult(ptr, limits[0], pin_name)
            result = self.getResult(value, limits[0])
            if result == AteCore.FAIL:
                # 超出最大可以容许的Limit, 必须Fail
                self.var.func_pass = False  # 这个是一个状态标志位
                ptr.TEST_FLG.set_test_failed()
                self.setBinResult(ptr, limits[0])
                Print.Danger(ptr.__str__())
            else:
                self.setBinLevelPassResult(limits[0])
                Print.Success(ptr.__str__())
            self.var.ptr_list.append(ptr)
            return

        for index, limit in enumerate(limits):
            ptr = Ptr(
                HEAD_NUM=self.var.prr.HEAD_NUM,
                SITE_NUM=self.var.dut,
            )
            ptr.set_value(value)
            if pin_name is None:
                _pin_name = "_{}".format(limit.SET_BIN_NAME)
            else:
                _pin_name = pin_name + "_{}".format(limit.SET_BIN_NAME)
            self.setPtrResult(ptr, limit, _pin_name)
            result = self.getResult(value, limit)

            if index == 0:
                if result == AteCore.FAIL:
                    # 超出最大可以容许的Limit, 必须Fail
                    self.var.func_pass = False  # 这个是一个状态标志位
                    ptr.TEST_FLG.set_test_failed()
                    self.setBinResult(ptr, limit)
                    Print.Danger(ptr.__str__())
                else:
                    Print.Success(ptr.__str__())
            else:
                if not self.var.func_pass:
                    # ptr.TEST_FLG.set_test_failed()
                    self.setBinResult(ptr, limit)
                    Print.Danger(ptr.__str__())
                else:
                    if result == AteCore.FAIL:
                        self.setBinLevelPassResult(block_limit)
                        Print.Warning(ptr.__str__())
                    else:
                        Print.Success(ptr.__str__())
            block_limit = limit

            self.var.ptr_list.append(ptr)

    def JudgeParamsIndModel(self, value: float, limit_ref: Union[str, LimitClass], pin_name=None, ):
        """
        独立模型, 数据在处理过程中, Limit是独立分Bin的, 顺序从1级往下走
        如果Level1测试不过, 就尝试测试Level2,
        如果Level2测试不过, 就尝试测试Level3
        如果Level3测试不过，就判定为Fail. 所以最终是用的Level3的Limit显示了Fail的数据
        """
        if not isinstance(value, float):
            value = float(value)
        if isinstance(limit_ref, LimitClass):
            limits: List[LimitClass] = [limit_ref]
        else:
            limits: [LimitClass] = self.app_var.limit[limit_ref]
            if limits is None:
                raise Exception("Error, No Limit File By Key: {}".format(limit_ref))
        limits = sorted(limits, key=lambda x: x.SET_BIN_LEVEL, reverse=False)  # 等级从小到大
        length = len(limits)
        if length == 1:
            """
            直接比对, Fail就退出程序
            """
            ptr = Ptr(
                HEAD_NUM=self.var.prr.HEAD_NUM,
                SITE_NUM=self.var.dut,
            )
            ptr.set_value(value)
            self.setPtrResult(ptr, limits[0], pin_name)
            result = self.getResult(value, limits[0])
            if result == AteCore.FAIL:
                # 超出最大可以容许的Limit, 必须Fail
                self.var.func_pass = False  # 这个是一个状态标志位
                ptr.TEST_FLG.set_test_failed()
                self.setBinResult(ptr, limits[0])
                Print.Danger(ptr.__str__())
            else:
                self.setBinLevelPassResult(limits[0])
                Print.Success(ptr.__str__())
            self.var.ptr_list.append(ptr)
            return

        for index, limit in enumerate(limits):

            ptr = Ptr(
                HEAD_NUM=self.var.prr.HEAD_NUM,
                SITE_NUM=self.var.dut,
            )
            ptr.set_value(value)

            if pin_name is None:
                _pin_name = "_{}".format(limit.SET_BIN_NAME)
            else:
                _pin_name = pin_name + "_{}".format(limit.SET_BIN_NAME)

            self.setPtrResult(ptr, limit, _pin_name)

            result = self.getResult(value, limit)
            if result == AteCore.PASS:
                Print.Success(ptr.__str__())
                self.var.ptr_list.append(ptr)
                self.setBinLevelPassResult(limit)
                break
            if index == length - 1:
                self.var.func_pass = False  # 这个是一个状态标志位
                ptr.TEST_FLG.set_test_failed()
                self.setBinResult(ptr, limit)
                Print.Danger(ptr.__str__())
                self.var.ptr_list.append(ptr)

    def Dtr(self, message: str, save=False):
        if save:
            self.app_var.s_dtr(message)
            return
        self.var.dtr_list.append(
            message
        )

    def JudgeFunctions(self, value: bool, limit_name: str, pin_name=None, ):
        """
        TODO: wait update, 暂时可以使用Ptr先用着
        :param value:
        :param limit_name:
        :param pin_name:
        :return:
        """
        pass

    def JudgeEqual(self, value, equal_value, limit_name: str, pin_name=None, ):
        """
        TODO: wait update
        :param value:
        :param equal_value:
        :param limit_name:
        :param pin_name:
        :return:
        """
        pass

    def RecordData(self, **kwargs):
        """
        示例, 这个是存储一个扫描数据
        :return:
        """
        pass
